package top.guoziyang.mydb.backend.vm;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import top.guoziyang.mydb.backend.common.AbstractCache;
import top.guoziyang.mydb.backend.dm.DataManager;
import top.guoziyang.mydb.backend.tm.TransactionManager;
import top.guoziyang.mydb.backend.tm.TransactionManagerImpl;
import top.guoziyang.mydb.backend.utils.Panic;
import top.guoziyang.mydb.common.Error;

public class VersionManagerImpl extends AbstractCache<Entry> implements VersionManager {

    TransactionManager tm;
    DataManager dm;
    Map<Long, Transaction> activeTransaction;
    Lock lock;
    LockTable lt;

    public VersionManagerImpl(TransactionManager tm, DataManager dm) {
        super(0);
        this.tm = tm;
        this.dm = dm;
        this.activeTransaction = new HashMap<>();
        activeTransaction.put(TransactionManagerImpl.SUPER_XID, Transaction.newTransaction(TransactionManagerImpl.SUPER_XID, 0, null));
        this.lock = new ReentrantLock();
        this.lt = new LockTable();
    }

    /**
     * 在事务 xid 下读取资源 uid 的内容
     */
    @Override
    public byte[] read(long xid, long uid) throws Exception {
        lock.lock();
        Transaction t = activeTransaction.get(xid);
        lock.unlock();

        if(t.err != null) {
            throw t.err;
        }

        Entry entry = null;
        try {
            // VM继承了AbstractCache类并重写了getForCache和releaseForCache方法，返回值类型是Entry
            entry = super.get(uid);
        } catch(Exception e) {
            if(e == Error.NullEntryException) {
                return null;
            } else {
                throw e;
            }
        }
        try {
            // 如果entry对当前事务t可见
            if(Visibility.isVisible(tm, t, entry)) {
                // 返回entry的有效数据部分
                return entry.data();
            } else {
                return null;
            }
        } finally {
            entry.release();
        }
    }

    /**
     * 在事务 xid 下插入数据
     */
    @Override
    public long insert(long xid, byte[] data) throws Exception {
        lock.lock();
        Transaction t = activeTransaction.get(xid);
        lock.unlock();

        if(t.err != null) {
            throw t.err;
        }
        // 封装新Entry的字节结构
        byte[] raw = Entry.wrapEntryRaw(xid, data);
        // 插入数据到缓存数据页：Entry封装到DataItem字节结构中，再把DataItem写入缓存中的数据页中
        return dm.insert(xid, raw);
    }

    /**
     * 在事务 xid 下删除指定uid数据
     */
    @Override
    public boolean delete(long xid, long uid) throws Exception {
        lock.lock();
        Transaction t = activeTransaction.get(xid);
        lock.unlock();

        if(t.err != null) {
            throw t.err;
        }
        Entry entry = null;
        try {
            // 获取指定的uid资源
            entry = super.get(uid);
        } catch(Exception e) {
            // 抛出异常，删除操作失败
            if(e == Error.NullEntryException) {
                return false;
            } else {
                throw e;
            }
        }
        try {
            // 如果entry资源对当前事务t不可见，返回false，删除失败
            if(!Visibility.isVisible(tm, t, entry)) {
                return false;
            }
            Lock l = null;
            try {
                //添加锁，确保当前事务对该记录的独占访问
                l = lt.add(xid, uid);
            } catch(Exception e) {
                // 调用 internAbort(xid, true) 自动中止事务，设置事务状态为已中止，并抛出异常
                t.err = Error.ConcurrentUpdateException;
                // 出现死锁，回滚事务
                internAbort(xid, true);
                t.autoAborted = true;
                throw t.err;
            }
            if(l != null) {
                l.lock();
                l.unlock();
            }
            // 如果entry的xmax等于当前事务id，说明记录已经被当前事务删除过，无需重复操作
            if(entry.getXmax() == xid) {
                return false;
            }
            // entry对当前事务可见，且xid != xmax,判断是否发生版本跳跃问题,如果发生版本跳跃，设置事务错误并中止当前事务
            if(Visibility.isVersionSkip(tm, t, entry)) {
                t.err = Error.ConcurrentUpdateException;
                // 发生版本跳跃，回滚事务
                internAbort(xid, true);
                t.autoAborted = true;
                throw t.err;
            }
            // 将记录的 Xmax 设置为当前事务 ID，逻辑上标记该记录已被删除
            entry.setXmax(xid);
            return true; // 删除成功

        } finally {
            entry.release(); // 释放资源
        }
    }

    /**
     * 开启一个事务，并初始化事务的结构，将其存放在 activeTransaction 中，用于检查和快照使用
     */
    @Override
    public long begin(int level) {
        lock.lock();
        try {
            // 开启一个新事物，并返回新事务的xid
            long xid = tm.begin();
            // 创建新事务xid的实例
            Transaction t = Transaction.newTransaction(xid, level, activeTransaction);
            activeTransaction.put(xid, t); // 把xid存入当前活跃事务Map中
            return xid;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 提交一个事务，主要就是 free 掉相关的结构，并且释放持有的锁，并修改 TM 状态
     */
    @Override
    public void commit(long xid) throws Exception {
        lock.lock();
        Transaction t = activeTransaction.get(xid);
        lock.unlock();
        // 验证事务是否存在异常,没有异常才能提交
        try {
            if(t.err != null) {
                throw t.err;
            }
        } catch(NullPointerException n) {
            System.out.println(xid);
            System.out.println(activeTransaction.keySet());
            Panic.panic(n);
        }

        lock.lock();
        // 把xid从当前活跃事务Map中移除
        activeTransaction.remove(xid);
        lock.unlock();

        lt.remove(xid); // 移除xid对应的锁
        tm.commit(xid); // 设置事务状态为已提交
    }

    /**
     * 手动中止(回滚)事务
     */
    @Override
    public void abort(long xid) {
        internAbort(xid, false);
    }

    /**
     * 该方法是一个事务中止（回滚）的内部实现(private修饰)，用于处理事务失败时的回滚、状态更新和资源释放。
     * autoAborted: 是否是系统自动中止的
     */
    private void internAbort(long xid, boolean autoAborted) {
        lock.lock();
        Transaction t = activeTransaction.get(xid);
        // 如果事务不是自动终止的(手动中止)
        if(!autoAborted) {
            // 将事务从活动事务表中移除
            activeTransaction.remove(xid);
        }
        lock.unlock();
        //检查事务是否已自动中止
        if(t.autoAborted){
            //如果事务 t 已经标记为自动中止，则直接返回，避免重复处理
            return;
        }
        // 移除事务xid 对应的锁
        lt.remove(xid);
        // 调整 xid 的状态为中止
        tm.abort(xid);
    }

    /**
     * 释放entry关联的数据项
     */
    public void releaseEntry(Entry entry) {
        super.release(entry.getUid());
    }

    /**
     * Entry资源不在缓存时的读取行为
     */
    @Override
    protected Entry getForCache(long uid) throws Exception {
        Entry entry = Entry.loadEntry(this, uid);
        if(entry == null) {
            throw Error.NullEntryException;
        }
        return entry;
    }

    /**
     * Entry资源被缓存驱逐时的行为
     */
    @Override
    protected void releaseForCache(Entry entry) {
        entry.remove();
    }
    
}
